In [75]:
recipe = """
[make 1 dot]
[move 1 space]
[turn 1 degree]
[repeat 170 times]
"""
In [1]:
import bokeh.plotting as bk
from math import cos, sin
from numpy import deg2rad
In [2]:
bk.output_notebook()
In [50]:
from functools import wraps
def instruction(func):
@wraps(func)
def wrapped(*args, **kwargs):
extras = {}
if 'inst' in kwargs:
parts = kwargs.pop('inst')
for color in 'red green blue pink purple white black'.split():
if color in parts:
extras['color'] = color
break
if 'tiny' in parts:
extras['size'] = 1
elif 'small' in parts:
extras['size'] = 3
elif 'medium' in parts:
extras['size'] = 10
elif 'big' in parts:
extras['size'] = 20
elif 'huge' in parts:
extras['size'] = 40
kwargs.update(extras)
return func(*args, **kwargs)
return wrapped
In [79]:
debug = False
class Turtle:
def __init__(self, point=(0,0),
direction=200.0,
turn_angle=1.0,
step=1.0):
self.point = point
self.direction = direction
self.direction %= 360.0
self.turn_angle = turn_angle
self.step = step
def turn(self, amount=None):
if not amount:
amount = self.turn_angle
self.direction += amount
def right(self):
self.direction -= 90.0
self.direction %= 360.0
def left(self):
self.direction += 90.0
self.direction %= 360.0
def flip(self):
self.direction -= 180.0
self.direction %= 360.0
def move(self, amount=None):
if not amount:
amount = self.step
self.last_point = self.point
self.point = (self.point[0] + self.step*cos(deg2rad(self.direction)),
self.point[1] + self.step*sin(deg2rad(self.direction)))
def goto(self, x, y):
self.point = (x, y)
@instruction
def dot(self, color='red', size=10):
self.fig.scatter([self.point[0]],
[self.point[1]],
color=color, s=size)
@instruction
def line(self, color='blue', size=3):
self.fig.line([self.last_point[0], self.point[0]],
[self.last_point[1], self.point[1]],
color=color, size=size)
def make_recipe(self, recipe):
self.fig = bk.figure(plot_width=400, plot_height=400,
tools = "pan,box_zoom,reset,resize,save",
#x_axis_type=None, y_axis_type=None,
min_border=0, outline_line_color=None,
title="Turtle Shell")
self.fig.grid.grid_line_color = None
self.fig.axis.axis_line_color = None
self.fig.axis.minor_tick_line_color = None
instructions = recipe.splitlines()
count = self.do(instructions[-1])
if count:
instructions.pop() # remove the last instruction
else:
count = 1 # there is no repeat, so just do recipe once
for i in range(count):
if debug: print "Doing {n} instructions:".format(n=len(instructions))
for instruction in instructions:
self.do(instruction)
bk.show(self.fig)
def do(self, instruction):
if not instruction or instruction.startswith('#'):
return
if not (instruction.startswith('[') and instruction.endswith(']')):
print "Skipping bad instruction:\n\t",
print instruction,
return
if debug: print "\tinstruction", instruction
#print "\t\t", self
# we have a good instruction: figure it out
parts = instruction[1:-1].split()
first = parts[0]
last = parts[-1]
rest = parts[1:]
if first == "repeat" and last == "times":
return int(parts[1])
elif first == "turn":
self.turn()
elif first == "move":
self.move()
elif first == "make":
if last == "dot":
self.dot(inst=parts)
if last == "line":
self.line(inst=parts)
def __str__(self):
return ("point({x}, {y}) ".format(x=self.point[0], y=self.point[1]) +
"direction({d}) ".format(d=self.direction) +
"angle({a}) ".format(a=self.turn_angle) +
"step({s})".format(s=self.step))
In [77]:
t = Turtle()
In [78]:
t.make_recipe(recipe)